package org.cellstore.dao;

import java.io.Serializable;
import java.util.List;
import javax.persistence.Table;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.palituxd.tools.eval.Evaluador;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

/**
 *
 * @author pablojesus
 */
@Repository
public abstract class AbstractDao<T> extends HibernateDaoSupport {

    private Class<T> entityClass;
    Transaction tx;
    public Session s;
    static Logger verlog = LoggerFactory.getLogger(AbstractDao.class);
    private SessionFactory sesionFactory;

    @Autowired
    public void setSesionFactory(SessionFactory sessionFactory) {
        this.sesionFactory = sessionFactory;
        super.setSessionFactory(this.sesionFactory);
    }

    public AbstractDao(Class<T> entityClass) {
        this.entityClass = entityClass;

    }

    public void abrirSession() {
        s = getHibernateTemplate().getSessionFactory().openSession();
    }

    public void cerrarSesion() {
        try {
            if (s.isOpen()) {
                s.close();
            }
        } catch (SessionException e) {
        }
    }

    public void crear(T entity) throws RuntimeException {
        try {
            abrirSession();
            tx = s.beginTransaction();
            tx.begin();

            s.persist(entity);//getHibernateTemplate().persist(entity);
            tx.commit();
        } catch (RuntimeException e) {
            verlog.error("AbstractFacade-------->" + e.getMessage());
            if (tx != null) {
                tx.rollback();
            }
            throw e;
        } finally {
            cerrarSesion();
        }
    }

    public void editar(T entity) throws RuntimeException {
        try {
            abrirSession();
            tx = s.beginTransaction();
            tx.begin();
            s.update(entity);//getHibernateTemplate().update(entity);
            tx.commit();
        } catch (RuntimeException e) {
            verlog.error("AbstractFacade-------->" + e.getMessage());
            if (tx != null) {
                tx.rollback();
            }
            throw e;
        } finally {
            cerrarSesion();
        }
    }

    public void remover(T entity) throws RuntimeException {
        try {
            abrirSession();
            tx = s.beginTransaction();
            tx.begin();
            s.delete(entity);//getHibernateTemplate().delete(entity);
            tx.commit();
        } catch (RuntimeException e) {
            verlog.error("AbstractFacade-------->" + e.getMessage());
            if (tx != null) {
                tx.rollback();
            }
            throw e;
        } finally {
            cerrarSesion();
        }
    }

    public T obtener(Object id) {
        T obj = null;
        try {
            obj = (T) getHibernateTemplate().get(entityClass, (Serializable) id);
        } catch (Exception e) {
            verlog.error("AbstractFacade-------->" + e.getMessage());
        }
        return obj;
    }

    public List<T> obtenerTodos() {
        List<T> lista = null;
        try {
            abrirSession();
            Criteria cq = s.createCriteria(entityClass);
            lista = cq.list();
        } catch (RuntimeException e) {
            verlog.error("AbstractFacade-------->" + e.getMessage());
        } finally {
            cerrarSesion();
        }
        return lista;
    }

    public List<T> obtenerEnRango(int[] range) {
        return null;
    }

    public int contador() {
        int num = -1;
        try {
            abrirSession();
            num = ((Long) s.createQuery("select count(*) from " + entityClass.getSimpleName()).iterate().next()).intValue();
        } catch (RuntimeException e) {
            verlog.error("AbstractFacade-------->" + e.getMessage());
        } finally {
            cerrarSesion();
        }
        return num;
    }

    public List<T> obtener(String nombreCampo, String valor) {
        List<T> lista = null;
        if (Evaluador.estaVacio(nombreCampo.toString()) || Evaluador.estaVacio(valor.toString())) {
            lista = obtenerTodos();
        } else {
            abrirSession();
            lista = s.createSQLQuery("SELECT * FROM " + entityClass.getAnnotation(Table.class).name() + " WHERE " + nombreCampo + " LIKE ? ").addEntity(entityClass).setString(0, "%" + valor + "%").list();
            cerrarSesion();
        }
        return lista;
    }
}
